#pragma once
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>

using boost::asio::io_service;   
using boost::asio::ip::tcp;

#define _RECV_BUF_SIZE_ 1024

class ITCPClient
{
public:
    virtual void onTcpConnect(bool connected) = 0;
    virtual void onClientMsg(void *pData,int nLen) = 0;
};


class tcp_client   
{   
public:   
    tcp_client (io_service  * io_service_,ITCPClient * pIClient)
    {
        m_pIClient = pIClient;
	    m_io_service = io_service_;
        m_socket     = new tcp::socket(*m_io_service);

    }

    void connect(const std::string & hostname, unsigned short port)
    {
        tcp::resolver        resolver(*m_io_service);     
        boost::system::error_code ec;   
	    tcp::resolver::query query(hostname, boost::lexical_cast<std::string, unsigned short>(port));   
	    tcp::resolver::iterator iter = resolver.resolve(query, ec);   
        tcp::resolver::iterator end;   
  
        // pick the first endpoint   
        if (iter != end && ec == 0)   
        {   
            tcp::endpoint endpoint = *iter;   

		    std::cout << "Connecting to: " << endpoint << std::endl;   
  
            m_socket->connect(endpoint, ec); 
		    memset(m_data,0,sizeof(m_data));
		    m_socket->async_read_some(boost::asio::buffer(m_data,_RECV_BUF_SIZE_),
			    boost::bind(&tcp_client::OnRecv,this,
			    boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
            if (ec)   
            {   
                std::cerr << "Error: " << ec << std::endl;   
                throw ec;   
                OutputDebugString(L"[Err]socket connect fail!\n");
                if(m_pIClient)
                    m_pIClient->onTcpConnect(false);

            }
            else
            {
                OutputDebugString(L"[Client][Detail]socket connect ok!\n");
                if(m_pIClient)
                    m_pIClient->onTcpConnect(true);
            }

        }   
    }
  
    virtual ~tcp_client()
    {   
        delete m_socket;   
        delete m_io_service;
    }   
  
    // methods   
	virtual void PostSend (char *data,int nSize)
    {   
	    m_socket->async_write_some(boost::asio::buffer(data,nSize),
		    boost::bind(&tcp_client::OnSend,this,
		    boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
    }

	//event call
    virtual bool OnRecv (const boost::system::error_code& error,size_t bytes_transferred)
    {
        if(!error)
        {
			std::string strRecv = (char *)m_data;
			
			std::cout<<strRecv<<std::endl;   

            //MSG_PUMP->OnMsg(m_data,bytes_transferred);

			memset(m_data,0,sizeof(m_data));
			m_socket->async_read_some(boost::asio::buffer(m_data,_RECV_BUF_SIZE_),
                boost::bind(&tcp_client::OnRecv,this,
                boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
        }
        else
        {
            //OnClose(error);

			return false;
        }
		return true;
    }
	virtual bool OnSend(const boost::system::error_code& error,size_t bytes_transferred)
    {
	    std::cout<<"Send Bytes:"<<bytes_transferred<<std::endl;
	    if(error)
	    {
		    OnClose(error);
		    return false;
	    }
	    return true;
    }
    virtual void OnClose (const boost::system::error_code& error)
    {   
        m_socket->close(); 
    }  
private:   
    io_service  * m_io_service;
    tcp::socket * m_socket; 
	char          m_data[_RECV_BUF_SIZE_];
    ITCPClient  * m_pIClient;
};   
